/**
 * 
 */
package com.app.gameserver.service.http;

import java.util.UUID;

import org.apache.log4j.Logger;

import com.app.framework.context.ActionRequest;
import com.app.framework.exception.ClientException;
import com.app.framework.exception.ORMException;
import com.app.framework.http.HttpContext;
import com.app.framework.http.HttpResponse;
import com.app.framework.orm.session.PersistenceSession;
import com.app.framework.util.ErrorCodeConstants;
import com.app.framework.util.StringUtils;

/**
 * @author lisong
 * @version 2013-3-13 下午1:58:14
 */
public class SessionServiceImpl implements SessionService {

	final static Logger logger = Logger.getLogger(SessionServiceImpl.class);
	@Override
	public void createSession(long userId,HttpContext context) throws Exception {
		if(!CHECK_SESSION) {
			return;
		}
		PersistenceSession persistenceSession = context.getPerssistenceSession();
		if(userId <= 0) {
			throw new ORMException("userId is null",ErrorCodeConstants.CLIENT_ERROR_USERID_NULL);
		}
		String memkey = genSessionKey(userId);
		String sessionId = UUID.randomUUID().toString();
		try {
			if(!persistenceSession.lockRecord(memkey)) {
				throw new ORMException("session create fail",ErrorCodeConstants.SERVER_ERROR_SESSION_CREATE_FAIL); 
			}
			persistenceSession.putOnlyCache(memkey, genSessionValue(sessionId, 1), SESSION_TIMEOUT);
			HttpResponse httpResponse = (HttpResponse) context.getResponse();
			httpResponse.setRequestId(0);
			httpResponse.setSessionId(sessionId);
		}finally {
			if(!persistenceSession.releaseRecord(memkey)) {
				logger.error("session lock release fail");
			}
		}
	}

	/**
	 * 生成session value
	 * @param sessionId
	 * @param lastReqId 下一次要请求的requestId
	 * @return
	 */
	private String genSessionValue(String sessionId,int nextReqId) {
		StringBuilder buffer = new StringBuilder();
		buffer.append(sessionId).append(":").append(nextReqId);
		return buffer.toString();
	}
	/**
	 * 生成session key
	 * @param userUid
	 * @return
	 */
	private String genSessionKey(long userId) {
		StringBuilder sb = new StringBuilder();
		sb.append(SESSION_KEY);
		sb.append("|");
		sb.append(userId);
		return sb.toString();
	}

	@Override
	public void checkSession(HttpContext context) throws Exception {
		
		ActionRequest request = (ActionRequest)context.getRequest();
		
		PersistenceSession persistenceSession = context.getPerssistenceSession(); 
		
		if(StringUtils.isNullOrEmpty(request.getSessionId())) {
			throw new ClientException("session not create",ErrorCodeConstants.CLIENT_ERROR_SESSION_NOT_CREATE);
		}
		
		String memkey = genSessionKey(request.getUserId());

		try {
			//循环十次
			boolean lock = false;
		
			for(int i=0;i<10;i++) {
				
				lock = persistenceSession.lockRecord(memkey);

				if(lock) {
					break;
				}
				
				Thread.sleep(1);
				
				StringBuilder buffer = new StringBuilder();
				
				buffer.append("checkSession thread sleep 1ms times:").append(i+1).append(",key:").append(memkey);
				
				logger.error(buffer.toString());
				
			}
			if(!lock) {
				
				StringBuilder buffer = new StringBuilder();
				
				buffer.append("action request too fast key:").append(memkey);
				
				String msg = buffer.toString();
				
				logger.error(msg);
				
				throw new ClientException(msg,ErrorCodeConstants.CLIENT_ERROR_ACTION_REQUEST_TOO_FAST);
			}
			
			String sessionValue = persistenceSession.getOnlyCache(memkey);

			if(StringUtils.isNullOrEmpty(sessionValue)) {//session失效
				
				StringBuilder buffer = new StringBuilder();
				
				buffer.append("session expired key:").append(memkey);
				
				String msg = buffer.toString();
				
				logger.error(msg);
				
				throw new ClientException(msg,ErrorCodeConstants.CLIENT_ERROR_SESSION_EXPIRED);
			}
			
			String sid = sessionValue.substring(0,sessionValue.indexOf(":"));

			if(!request.getSessionId().equals(sid)) {
				
				StringBuilder buffer = new StringBuilder();
				
				buffer.append("other login key:").append(memkey);
				
				String msg = buffer.toString();
				
				logger.error(msg);
				
				throw new ClientException(msg,ErrorCodeConstants.CLIENT_ERROR_OTHER_LOGIN);
			}
			
			int lastId = Integer.parseInt(sessionValue.substring(sid.length() + 1));

			if(request.getRequestId() > 0) {//如果客户端提交的请求序列号等于0则认为该请求为异步请求 不判断重复执行
				
				if(lastId != request.getRequestId()) {
					((HttpResponse)context.getResponse()).setRequestId(lastId - 1);
					
					StringBuilder buffer = new StringBuilder();
					
					buffer.append("action already executed key:").append(memkey);
					
					String msg = buffer.toString();
					
					logger.error(msg);
					
					throw new ClientException(msg,ErrorCodeConstants.CLIENT_ERROR_REQUEST_EXECUTED);
				}

				lastId ++;
				
			}
			
			((HttpResponse)context.getResponse()).setRequestId(lastId - 1);
			
			persistenceSession.putOnlyCache(memkey, genSessionValue(sid, lastId), SESSION_TIMEOUT);

		} finally {
			if(!persistenceSession.releaseRecord(memkey)) {
				
				StringBuilder buffer = new StringBuilder();
				
				buffer.append("session lock release fail key:").append(memkey);
				
				logger.error(buffer.toString());
			}
		}
	}
}
